// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

#include "coin2/exchange/factory/feed/raw_processor.h"

#include <memory>
#include <string>

#include "coin2/base/log.h"
#include "coin2/exchange/base/market/enums.h"
#include "coin2/exchange/binance_base/feed_v1/processor.h"
#include "coin2/exchange/bitflyer_futures/feed_v1/processor.h"
#include "coin2/exchange/bithumb/feed_v2/processor.h"
#include "coin2/exchange/bitmex/feed_v1/processor.h"
#include "coin2/exchange/bitstamp/feed_v2/processor.h"
#include "coin2/exchange/bybit/feed_v1/processor.h"
#include "coin2/exchange/bybit/feed_v3/processor.h"
#include "coin2/exchange/bybit_futures/feed_v2/processor.h"
#include "coin2/exchange/bybit_futures/feed_v3/processor.h"
#include "coin2/exchange/coinone/feed_v2/processor.h"
#include "coin2/exchange/di/constant.h"
#include "coin2/exchange/ftx_common/feed_v1/processor.h"
#include "coin2/exchange/gdax/feed_v1/processor.h"
#include "coin2/exchange/gopax/feed_v1/processor.h"
#include "coin2/exchange/huobi/feed_v1/processor.h"
#include "coin2/exchange/huobi_futures/feed_v1/processor.h"
#include "coin2/exchange/kraken/feed_v1/processor.h"
#include "coin2/exchange/okex_common/feed_v3/processor.h"
#include "coin2/exchange/okex_common/feed_v5/processor.h"
#include "coin2/exchange/prex_base/feed_v1/processor.h"
#include "coin2/exchange/quoinex/feed_v2/processor.h"
#include "coin2/exchange/upbit/feed_v1/processor.h"
#include "coin2/exchange/korbit/feed_v1/processor.h"
#include "coin2/exchange/bitbank/feed_v1/processor.h"
#include "coin2/exchange/lmax_digital/feed_v1/processor.h"
#include "coin2/exchange/deribit_base/feed_v2/processor.h"
#include "coin2/exchange/coincheck/feed_v1/processor.h"
#include "coin2/exchange/uniswap/feed_v3/processor.h"
#include "coin2/exchange/gateio/feed_v4/processor.h"
#include "coin2/exchange/phemex_base/feed_v1/processor.h"
#include "coin2/exchange/kucoin/feed_v1/processor.h"
#include "coin2/exchange/kucoin_futures/feed_v1/processor.h"
#include "coin2/exchange/dydx_futures/feed_v3/processor.h"
#include "coin2/exchange/pancakeswap/feed_v2/processor.h"
#include "coin2/exchange/btcturk/feed_v1/processor.h"
#include "coin2/exchange/crypto_common/feed_v2/processor.h"
#include "coin2/exchange/mexc/feed_v2/processor.h"
#include "coin2/exchange/mexc/feed_v3/processor.h"
#include "coin2/exchange/mexc_futures/feed_v1/processor.h"
#include "coin2/exchange/coingecko/feed_v3/processor.h"
#include "coin2/exchange/bitget/feed_v1/processor.h"
#include "coin2/exchange/lbank/feed_v2/processor.h"
#include "coin2/exchange/mercado/feed_v4/processor.h"
#include "coin2/exchange/bitmart/feed_v3/processor.h"
#include "coin2/exchange/bit/feed_v1/processor.h"
#include "coin2/exchange/maicoin/feed_v2/processor.h"
#include "coin2/exchange/bittrex/feed_v3/processor.h"

using namespace coin2::exchange::base::symbology;
using namespace coin::proto;

namespace coin2::exchange::factory::feed::impl {

std::unique_ptr<base::feed::FeedParsingProcessor> NewRawProcessor(
    const coin2::exchange::di::ConstantInjection& ci,
    const std::string& system_name,
    const MarketExchangeApi& mea,
    const ::coin2::exchange::feed::RawParserConfig& config,
    const std::string& recipe) {
  if (mea == MarketExchangeApi{Spot, ExchangeType::Huobi, "v1"} ||
      mea == MarketExchangeApi{Spot, ExchangeType::Huobi, "v1-mbp5"}) {
    return std::make_unique<huobi::feed_v1::HuobiFeedProcessor>(system_name, ci, config, mea);
  } else if (
      mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1"} ||
      mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-swap"} ||
      mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-noti"} ||
      mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-swap-noti"} ||
      mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-linear-swap"}) {
    return std::make_unique<huobi_futures::feed_v1::HuobiFuturesFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi {Futures, Bitmex, "v1"}) {
    return std::make_unique<bitmex::feed_v1::BitmexFeedProcessor>(system_name, ci, config);
  } else if (
      mea == MarketExchangeApi{Spot, Okex, "v3"} || mea == MarketExchangeApi{Futures, Okex, "v3"} ||
      mea == MarketExchangeApi{Futures, Okex, "v3-swap"}) {
    return std::make_unique<okex_common::feed_v3::OkexCommonFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (
      mea == MarketExchangeApi{Spot, Okex, "v5"} || mea == MarketExchangeApi{Futures, Okex, "v5"} ||
      mea == MarketExchangeApi{Futures, Okex, "v5-swap"}) {
    return std::make_unique<okex_common::feed_v5::OkexCommonFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (
      (mea == MarketExchangeApi{Futures, Binance, "v1"}) ||
      (mea == MarketExchangeApi{Futures, Binance, "v1-delivery"}) ||
      (mea == MarketExchangeApi{Spot, Binance, "v1"}) ||
      (mea == MarketExchangeApi{Spot, Binanceus, "v1"})) {
    return std::make_unique<binance_base::feed_v1::BinanceBaseFeedProcessor>(
        system_name,
        mea,
        ci,
        config,
        recipe);
  } else if (mea == MarketExchangeApi{Spot, Kraken, "v1"}) {
    return std::make_unique<kraken::feed_v1::KrakenFeedProcessor>(system_name, ci, config);
  } else if (
      (mea == MarketExchangeApi{Spot, Upbit, "v1"}) ||
      (mea == MarketExchangeApi{Spot, Upbitsg, "v1"}) ||
      (mea == MarketExchangeApi{Spot, Upbitid, "v1"}) ||
      (mea == MarketExchangeApi{Spot, Upbitth, "v1"})) {
    return std::make_unique<upbit::feed_v1::UpbitFeedProcessor>(system_name, mea, ci, config);
  }else if (mea == MarketExchangeApi{Spot, Coinone, "v2"}) {
    return std::make_unique<coinone::feed_v2::CoinoneFeedProcessor>(system_name, ci, config);
  } else if (mea == MarketExchangeApi{Spot, Gdax, "v1"}) {
    return std::make_unique<gdax::feed_v1::GdaxFeedProcessor>(system_name, ci, config);
  } else if (mea == MarketExchangeApi{Spot, Gopax, "v1"}) {
    return std::make_unique<gopax::feed_v1::GopaxFeedProcessor>(system_name, ci, config);
  } else if (mea == MarketExchangeApi{Spot, Quoinex, "v2"}) {
    return std::make_unique<quoinex::feed_v2::QuoinexFeedProcessor>(system_name, ci, config);
  } else if (mea == MarketExchangeApi{Futures, Bitflyer, "v1"}) {
    return std::make_unique<bitflyer_futures::feed_v1::BitflyerFuturesFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Spot, Bitflyer, "v1"}) {
    return std::make_unique<bitflyer_futures::feed_v1::BitflyerFuturesFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (
      mea == MarketExchangeApi{Futures, Ftx, "v1"} || mea == MarketExchangeApi{Spot, Ftx, "v1"}) {
    return std::make_unique<ftx_common::feed_v1::FtxCommonFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Bithumb, "v2"}) {
    return std::make_unique<bithumb::feed_v2::BithumbFeedProcessor>(system_name, ci, config);
  } else if (mea == MarketExchangeApi{Spot, Bybit, "v1"}) {
    return std::make_unique<bybit_spot::feed_v1::BybitFeedProcessor>(system_name, ci, config, mea);
  } else if (
      mea == MarketExchangeApi{Futures, Bybit, "v2"} ||
      mea == MarketExchangeApi{Futures, Bybit, "v2-linear"}) {
    return std::make_unique<bybit_futures::feed_v2::BybitFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Bybit, "v3"}) {
    return std::make_unique<bybit::feed_v3::BybitFeedProcessor>(system_name, ci, config, mea);
  } else if (
      mea == MarketExchangeApi{Futures, Bybit, "v3"} ||
      mea == MarketExchangeApi{Futures, Bybit, "v3-linear"} ||
      mea == MarketExchangeApi{Futures, Bybit, "v3-linear-usdc"}) {
    return std::make_unique<bybit_futures::feed_v3::BybitFeedProcessor>(
        system_name,
        ci,
        config,
        mea,
        recipe);
  } else if (mea == MarketExchangeApi{Spot, Bitstamp, "v2"}) {
    return std::make_unique<bitstamp::feed_v2::BitstampFeedProcessor>(system_name, ci, config);
  } else if ((mea == MarketExchangeApi{Spot, Prex, "v1"}) ||
             (mea == MarketExchangeApi{Futures, Prex, "v1"})) {
    return std::make_unique<prex_base::feed_v1::PrexBaseFeedProcessor>(
        system_name, mea, ci, config);
  } else if (mea == MarketExchangeApi{Spot, Korbit, "v1"}) {
    return std::make_unique<korbit::feed_v1::KorbitFeedProcessor>(system_name, ci, config);
  } else if (mea == MarketExchangeApi{Spot, Bitbank, "v1"}) {
    return std::make_unique<bitbank::feed_v1::BitbankFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Spot, Lmaxdigital, "v1"}) {
    return std::make_unique<lmax_digital::feed_v1::LmaxdigitalFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Futures, Deribit, "v2"} ||
             mea == MarketExchangeApi{Options, Deribit, "v2"} ||
             mea == MarketExchangeApi{Index, Deribit, "v2"}) {
    return std::make_unique<deribit_base::feed_v2::DeribitBaseFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Coincheck, "v1"}) {
    return std::make_unique<coincheck::feed_v1::CoincheckFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Spot, Uniswap, "v3"} ||
             mea == MarketExchangeApi{Spot, Uniswap, "v3-arbitrum"} ||
             mea == MarketExchangeApi{Spot, Uniswap, "v2"}) {
    return std::make_unique<uniswap::feed_v3::UniswapFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Gateio, "v4"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4-btc"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4-delivery-btc"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4-delivery"}) {
    return std::make_unique<gateio::feed_v4::GateioFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Phemex, "v1"} ||
             mea == MarketExchangeApi{Futures, Phemex, "v1"} ||
             mea == MarketExchangeApi{Futures, Phemex, "v1-linear"}) {
    return std::make_unique<phemex_base::feed_v1::PhemexBaseFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Kucoin, "v1"}) {
    return std::make_unique<kucoin::feed_v1::KucoinFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Futures, Kucoin, "v1"}) {
    return std::make_unique<kucoin_futures::feed_v1::KucoinFuturesFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Futures, Dydx, "v3"}) {
    return std::make_unique<dydx_futures::feed_v3::DydxFuturesFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Pancakeswap, "v2"}) {
    return std::make_unique<pancakeswap::feed_v2::PancakeswapFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Spot, Btcturk, "v1"}) {
    return std::make_unique<btcturk::feed_v1::BtcturkFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Spot, Crypto, "v2"} ||
             mea == MarketExchangeApi{Futures, Crypto, "v1"}) {
    return std::make_unique<crypto_common::feed_v2::CryptoFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Mexc, "v2"}) {
    return std::make_unique<mexc::feed_v2::MexcFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Mexc, "v3"}) {
    return std::make_unique<mexc::feed_v3::MexcFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Futures, Mexc, "v1"}) {
    return std::make_unique<mexc_futures::feed_v1::MexcFuturesFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Coingecko, "v3"}) {
    return std::make_unique<coingecko::feed_v3::CoingeckoFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (
      (mea == MarketExchangeApi{Spot, Bitget, "v1"}) ||
      (mea == MarketExchangeApi{Futures, Bitget, "v1"})) {
    return std::make_unique<bitget::feed_v1::BitgetFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Lbank, "v2"}) {
    return std::make_unique<lbank::feed_v2::LbankFeedProcessor>(
        system_name,
        ci,
        config);
  } else if (
      (mea == MarketExchangeApi{Futures, Apollox, "v1"}) ||
      (mea == MarketExchangeApi{Spot, Apollox, "v1"})) {
    return std::make_unique<binance_base::feed_v1::BinanceBaseFeedProcessor>(
        system_name,
        mea,
        ci,
        config,
        recipe);
  } else if (mea == MarketExchangeApi{Spot, Mercado, "v4"}) {
    return std::make_unique<mercado::feed_v4::MercadoFeedProcessor>(
        system_name,
        mea,
        ci,
        config);
  } else if (mea == MarketExchangeApi{Spot, Bitmart, "v3"}) {
    return std::make_unique<bitmart::feed_v3::BitmartFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Bit, "v1"}) {
    return std::make_unique<bit::feed_v1::BitFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Maicoin, "v2"}) {
    return std::make_unique<maicoin::feed_v2::MaicoinFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else if (mea == MarketExchangeApi{Spot, Bittrex, "v3"}) {
    return std::make_unique<bittrex::feed_v3::BittrexFeedProcessor>(
        system_name,
        ci,
        config,
        mea);
  } else {
    THROW() << "[RawProcessor Factory] not implemented for " << mea.String();
  }
  return {};
}

}  // namespace coin2::exchange::factory::feed::impl
